package zone.czh.woi.woim.server.channel.handler;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import zone.czh.woi.protocol.protocol.Payload;
import zone.czh.woi.woim.base.channel.codec.PacketHandler;
import zone.czh.woi.woim.base.obj.vo.Packet;
import zone.czh.woi.woim.server.Exception.VerifyException;
import zone.czh.woi.woim.server.WOIMServer;
import zone.czh.woi.woim.server.constant.AttributeKeyConstant;
import zone.czh.woi.woim.server.util.AttributeKeyUtil;

import java.util.List;

/**
*@ClassName: AuthHandler
*@Description: None
*@author woi
*/
@Getter
@Setter
@Accessors(chain = true)
public class AuthHandler extends PacketHandler<Object> {
    private Logger log = LoggerFactory.getLogger(AuthHandler.class);

    private Verifier verifier;

    private WOIMServer.EventListener eventListener;

    WOIMServer woimServer;

    Barrier barrier;

    public AuthHandler() {
        super(Object.class);
    }

    @Override
    protected void handle(ChannelHandlerContext ctx, Packet<Object> packet, List<Object> out) throws Exception {
        Channel channel = ctx.channel();
        if (Payload.Cmd.AUTH.equals(packet.getCmd())){
            if (verifier!=null){
                Object token = packet.getData();
                try {
                    String cid = verifier.verify(channel,packet);
                    if (cid!=null){
                        AttributeKeyUtil.set(channel, AttributeKeyConstant.CHANNEL_ID,cid);
                        verifier.handleAuthSuccess(channel,packet);
                        if (eventListener!=null){
                            eventListener.onBeforeChannelBeingManaged(ctx.channel(),token);
                        }
                        woimServer.manage(channel,cid);
                        ctx.pipeline().remove(Barrier.class);
                        ctx.pipeline().remove(this);
                        if (eventListener!=null){
                            eventListener.onAfterChannelBeingManaged(ctx.channel(),token);
                        }
                    }else {
                        VerifyException e = new VerifyException("cid can not be null");
                        verifier.handleAuthFailed(channel,packet,e);
                        ctx.close();
                    }
                }catch (VerifyException e){
                    verifier.handleAuthFailed(channel,packet,e);
                }

            }else {
                ctx.close();
                throw new RuntimeException("verifier can not be null");
            }
        }else {
            out.add(packet);
        }
    }

    /**
     * 需要提供无参构造器
     */
    public interface Verifier {
        /**
         * 返回值为channel标识，将存入attr中，键值为AttributeKeyConstant.CHANNEL_ID
         * @param channel
         * @param packet
         * @return channel id
         */
        String verify(Channel channel, Packet packet) throws VerifyException;


        /**
         * 授权成功 可在此对channel进行属性设置等
         * @param channel
         * @param packet
         */
        void handleAuthSuccess(Channel channel, Packet packet);

        /**
         * 授权成功 可在此对channel进行属性设置等
         * @param channel
         * @param packet
         * @param e
         */
        void handleAuthFailed(Channel channel, Packet packet,VerifyException e);
    }

}
